3.2.3 Verilog HDL建模描述
(1)顶层文件step.v。
//*************************************************************
// File name : step
// Module name : step
//
// Author : STEP
// Date : 2023/3/31
// Version : V 1.0
// Description : 顶层模块。
//
// Modification history
//--------------------------------------------------------------------------
// $Log$
//
// *********************************************************************
module step
(
input rst_n , // system reset, active low
input fpga_rx ,
output fpga_tx //UART发送输出
);
HSOSC #(
.CLKHF_DIV ("0b10")
) OSCInst0 (
.CLKHFEN (1'b1 ),
.CLKHFPU (1'b1 ),
.CLKHF (clk)
);
wire rx_data_valid;
wire [7:0] rx_data;
wire tx_data_valid;
wire [7:0] tx_data;
//Uart_Bus module
Uart_Bus u1
(
.clk (clk ), //系统时钟 12MHz
.rst_n (rst_n ), //系统复位,低有效
//负责FPGA接收UART芯片的数据
.uart_rx (fpga_rx ), //UART接收输入
//负责FPGA发送数据给UART芯片
.step_data_valid (tx_data_valid ),
.step_data (tx_data ),
.uart_tx (fpga_tx )
);
control control_s
(
.clk (clk ), // system clock
.rst_n (rst_n ), // system reset, active low
.tx_data_valid (tx_data_valid ),
.tx_data_out (tx_data )
);
endmodule
(2)center_control.v。
// **************************************************************
// File name : center_control
// Module name : control
//
// Author : STEP
// Date : 2023/3/31
// Version : V 1.0
// Description : 负责将“step“给uart发送给上位机。
//
// Modification history
//--------------------------------------------------------------------------
// $Log$
//
// *********************************************************************
module control
(
input clk, // system clock
input rst_n, // system reset, active low
output reg tx_data_valid,
output reg [7:0] tx_data_out
);
reg temp_tx_flag;
reg [23:0] cnt_uart;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
temp_tx_flag <= 1'b1;
else if(cnt_uart == 24'd8_599_999)
temp_tx_flag <= 1'b0;
else
temp_tx_flag <= temp_tx_flag;
end
always @(posedge clk or negedge rst_n)begin //计数
if(!rst_n) cnt_uart <= 1'b0;
else if(cnt_uart >= 24'd11_999_999) cnt_uart <= 1'b0;
else if (temp_tx_flag) cnt_uart <= cnt_uart + 1'b1;
else cnt_uart <= 24'd0;
end
always @(posedge clk or negedge rst_n)begin //*********************每秒发一个温度时间数据,字符串显示***********************//
if(!rst_n) begin
tx_data_valid <= 1'b0;
tx_data_out <= 1'b0;
end
else begin
if(temp_tx_flag)begin //发送温度数据
if(cnt_uart == 24'd6_099_999 ) begin //发送s
tx_data_valid <= 1'b1;
tx_data_out <= {1'b0,7'h73};
end
else if(cnt_uart == 24'd6_599_999 ) begin //发送t
tx_data_valid <= 1'b1;
tx_data_out <= {1'b0,7'h74};
end
else if(cnt_uart == 24'd7_099_999 ) begin //发送e
tx_data_valid <= 1'b1;
tx_data_out <= {1'b0,7'h65};
end
else if(cnt_uart == 24'd7_599_999 ) begin //发送p
tx_data_valid <= 1'b1;
tx_data_out <= {1'b0,7'h70};
end
else if(cnt_uart == 24'd8_099_999 ) begin //换行
tx_data_valid <= 1'b1;
tx_data_out <= 8'd10;
end
else begin
tx_data_valid <= 1'b0; tx_data_out <= tx_data_out;
end
end
else begin
tx_data_valid <= 1'b0; tx_data_out <= 8'd0;
end
end
end
endmodule
(3)uart_bus.v。
// **************************************************************
// File name : uart_bus
// Module name : Uart_Bus
//
// Author : STEP
// Date : 2023/3/31
// Version : V 1.0
// Description : uart串口的顶层模块。
//
// Modification history
//--------------------------------------------------------------------------
// $Log$
//
// *********************************************************************
module Uart_Bus #
(
parameter BPS_PARA = 1250 //12MHz时钟时参数1250对应9600的波特率
)
(
input clk, //系统时钟 12MHz
input rst_n, //系统复位,低有效
input uart_rx, //UART接收输入
input step_data_valid, //发送数据有效脉冲
input [7:0] step_data, //要发送的数据
output uart_tx //UART发送输出
);
wire rx_data_valid; //接收数据有效脉冲
wire [7:0] rx_data_out; //接收到的数据
/////////////////////////////////UART接收功能模块例化////////////////////////////////////
wire bps_en_rx,bps_clk_rx;
//UART接收波特率时钟控制模块 例化
Baud #
(
.BPS_PARA (BPS_PARA )
)
Baud_rx
(
.clk (clk ), //系统时钟 12MHz
.rst_n (rst_n ), //系统复位,低有效
.bps_en (bps_en_rx ), //接收时钟使能
.bps_clk (bps_clk_rx ) //接收时钟输出
);
//UART接收数据模块 例化
Uart_Rx Uart_Rx_uut
(
.clk (clk ), //系统时钟 12MHz
.rst_n (rst_n ), //系统复位,低有效
.bps_en (bps_en_rx ), //接收时钟使能
.bps_clk (bps_clk_rx ), //接收时钟输入
.uart_rx (uart_rx ), //UART接收输入
.rx_data_valid (rx_data_valid ), //接收数据有效脉冲
.rx_data_out (rx_data_out ) //接收到的数据
);
/////////////////////////////////UART发送功能模块例化////////////////////////////////////
wire bps_en_tx,bps_clk_tx;
//UART发送波特率时钟控制模块 例化
Baud #
(
.BPS_PARA (BPS_PARA )
)
Baud_tx
(
.clk (clk ), //系统时钟 12MHz
.rst_n (rst_n ), //系统复位,低有效
.bps_en (bps_en_tx ), //发送时钟使能
.bps_clk (bps_clk_tx ) //发送时钟输出
);
//UART发送数据模块 例化
Uart_Tx Uart_Tx_uut
(
.clk (clk ), //系统时钟 12MHz
.rst_n (rst_n ), //系统复位,低有效
.bps_en (bps_en_tx ), //发送时钟使能
.bps_clk (bps_clk_tx ), //发送时钟输入
.step_data_valid (step_data_valid ), //step的有效脉冲
.step_data (step_data ), //step
.tx_data_valid (bps_en_rx ), //发送数据有效脉冲
.tx_data_in (rx_data_out ), //要发送的数据
.uart_tx (uart_tx ) //UART发送输出
);
endmodule
(4)uart_r。
// **************************************************************
// File name : uart_r
// Module name : Uart_Rx
//
// Author : STEP
// Date : 2023/3/31
// Version : V 1.0
// Description : uart串口的接收模块。
//
// Modification history
//--------------------------------------------------------------------------
// $Log$
//
// *********************************************************************
module Uart_Rx
(
input clk, //系统时钟 12MHz
input rst_n, //系统复位,低有效
output reg bps_en, //接收时钟使能
input bps_clk, //接收时钟输入
input uart_rx, //UART接收输入
output reg rx_data_valid, //接收数据有效脉冲
output reg [7:0] rx_data_out //接收到的数据
);
reg uart_rx0,uart_rx1,uart_rx2;
//多级延时锁存去除亚稳态
always @ (posedge clk) begin
uart_rx0 <= uart_rx;
uart_rx1 <= uart_rx0;
uart_rx2 <= uart_rx1;
end
//检测UART接收输入信号的下降沿
wire neg_uart_rx = uart_rx2 & ~uart_rx1;
reg [3:0] num;
//接收时钟使能信号的控制
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
bps_en <= 1'b0;
else if(neg_uart_rx && (!bps_en)) //当空闲状态(bps_en为低电平)时检测到UART接收信号下降沿,进入工作状态(bps_en为高电平),控制时钟模块产生接收时钟
bps_en <= 1'b1;
else if(num==4'd9) //当完成一次UART接收操作后,退出工作状态,恢复空闲状态
bps_en <= 1'b0;
end
reg [7:0] rx_data;
//当处于工作状态中时,按照接收时钟的节拍获取数据
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
num <= 4'd0;
rx_data <= 8'd0;
end else if(bps_en) begin
if(bps_clk) begin
num <= num + 1'b1;
if(num<=4'd8) rx_data[num-1] <= uart_rx1; //先接受低位再接收高位,8位有效数据
end else if(num == 4'd9) begin //完成一次UART接收操作后,将获取的数据输出
num <= 4'd0;
end
end else begin
num <= 4'd0;
end
end
//将接收的数据输出,同时控制输出有效信号产生脉冲
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
rx_data_out <= 8'd0;
rx_data_valid <= 1'b0;
end else if(num == 4'd9) begin
rx_data_out <= rx_data;
rx_data_valid <= 1'b1;
end else begin
rx_data_out <= rx_data_out;
rx_data_valid <= 1'b0;
end
end
endmodule
(5)uart_s。
// **************************************************************
// File name : uart_s
// Module name : Uart_Tx
//
// Author : STEP
// Date : 2023/3/31
// Version : V 1.0
// Description : uart串口的发送模块。
//
// Modification history
//--------------------------------------------------------------------------
// $Log$
//
// *********************************************************************
module Uart_Tx
(
input clk, //系统时钟 12MHz
input rst_n, //系统复位,低有效
output reg bps_en, //发送时钟使能
input bps_clk, //发送时钟输入
input step_data_valid,
input [7:0] step_data,
input tx_data_valid, //发送数据有效脉冲
input [7:0] tx_data_in, //要发送的数据
output reg uart_tx //UART发送输出
);
reg [3:0] num;
reg [9:0] tx_data_r; //融合了起始位和停止位的数据
reg [7:0] tx_data;
reg en_flag;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
tx_data <= 8'd0;
en_flag <= 1'b0;
end
else if(step_data_valid)begin
tx_data <= step_data;
en_flag <= 1'b1;
end
else if(tx_data_valid)begin
tx_data <= tx_data_in;
en_flag <= 1'b1;
end
else begin
tx_data <= 8'd0;
en_flag <= 1'b0;
end
end
//驱动发送数据操作
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
bps_en <= 1'b0;
tx_data_r <= 10'd0;
end else if(en_flag && (!bps_en))begin
bps_en <= 1'b1; //当检测到接收时钟使能信号的下降沿,表明接收完成,需要发送数据,使能发送时钟使能信号
tx_data_r <= {1'b1,tx_data,1'b0};
end else if(num==4'd10) begin
bps_en <= 1'b0; //一次UART发送需要10个时钟信号,然后结束
end
end
//当处于工作状态中时,按照发送时钟的节拍发送数据
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
num <= 1'b0;
uart_tx <= 1'b1;
end else if(bps_en) begin
if(bps_clk) begin
num <= num + 1'b1;
uart_tx <= tx_data_r[num];
end else if(num>=4'd10) begin
num <= 4'd0;
end
end
end
endmodule
(6)Baud.v。
// **************************************************************
// File name : Baud
// Module name : Baud
//
// Author : STEP
// Date : 2023/3/31
// Version : V 1.0
// Description : 产生波特率节拍,给uart发送和接收模块产生相应的波特率节拍信号。
//
// Modification history
//--------------------------------------------------------------------------
// $Log$
//
// *********************************************************************
module Baud #
(
parameter BPS_PARA = 1250 //12MHz时钟时参数1250对应9600的波特率
)
(
input clk, //系统时钟
input rst_n, //系统复位,低有效
input bps_en, //接收或发送时钟使能
output reg bps_clk //接收或发送时钟输出
);
reg [12:0] cnt;
//计数器计数满足波特率时钟要求
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 1'b0;
else if((cnt >= BPS_PARA-1)||(!bps_en)) //当时钟信号不使能(bps_en为低电平)时,计数器清零并停止计数
cnt <= 1'b0; //当时钟信号使能时,计数器对系统时钟计数,周期为BPS_PARA个系统时钟周期
else
cnt <= cnt + 1'b1;
end
//产生相应波特率的时钟节拍,接收模块将以此节拍进行UART数据接收
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
bps_clk <= 1'b0;
else if(cnt == (BPS_PARA>>1)) //右移一位等于除以2,终值BPS_PARA为数据更替点,中值数据稳定,做采样点
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
end
endmodule